package org.compiere.process;

import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.logging.Level;

import org.adempiere.exceptions.AdempiereException;
import org.compiere.model.Mhrmabsence;
import org.compiere.model.Mhrmattendance;
import org.compiere.model.Mhrmbonus;
import org.compiere.model.Mhrmbusinesstrip;
import org.compiere.model.Mhrmemployee;
import org.compiere.model.Mhrmemployeessigned;
import org.compiere.model.Mhrmintercheckoff;
import org.compiere.model.Mhrmlimitholiday;
import org.compiere.model.Mhrmmaterialaid;
import org.compiere.model.Mhrmorder;
import org.compiere.model.Mhrmreview;
import org.compiere.model.Mhrmsettax;
import org.compiere.model.Mhrmvacation;
import org.compiere.model.MhrmwageRate;
import org.compiere.model.PO;
import org.compiere.model.X_hrm_absence;
import org.compiere.model.X_hrm_attendance;
import org.compiere.model.X_hrm_limitholiday;
import org.compiere.model.X_hrm_order;
import org.compiere.model.X_hrm_set_tax;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.eevolution.model.MHRJob;
import org.eevolution.model.X_HR_Contract;
import org.eevolution.model.X_HR_Employee;
import org.joda.time.DateTime;

import extend.org.compiere.utils.Util;

/**
 * Processing orders
 * @author V.Sokolov
 *
 */
public class ProcessOrders extends SvrProcess {
	
	/** */
	private Mhrmorder hrmorder = null;
	private Mhrmorder hrmorderref = null;
	/** */
	MhrmwageRate wageRate = null;
	/** limit holiday*/
	X_hrm_limitholiday holiDaylimit = null;
	/**	Employee Lines	*/
	private Mhrmemployee[] linesEmployee;
	/**	Signed Lines	*/
	private Mhrmemployeessigned[] linesSigned;
	/** Error message */
	private StringBuilder errmsg = new StringBuilder();
	private long ShiftTime = 0;

	@Override
	protected void prepare() {
		hrmorder = new Mhrmorder(getCtx(), getRecord_ID(), get_TrxName());
	}
	
	//* Checking the number of employees in order */
	private void selectedEmployee(int cnt){
		if(cnt > 1)
			throw new AdempiereException(Msg.translate(Env.getCtx(), "NotSelectedEmployee"));
	}

	@Override
	protected String doIt() throws Exception {
		
		//
		X_HR_Employee hremp = null;
		Mhrmemployee hrmempl = null;
		Mhrmabsence absence = null;
		Mhrmattendance attendance = null;
		Mhrmbusinesstrip btrip = null;
		Mhrmvacation vacation = null;
		Mhrmbonus bonus = null;
		Mhrmreview review = null;
		Mhrmmaterialaid maid = null;
		Mhrmintercheckoff inter = null;
		DateTime maxDt = Util.MAX_DATE;
		DateTime minDt = new DateTime("2008-01-18");
		Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); 
		//
		linesEmployee = hrmorder.getLinesEmployee();
		linesSigned = hrmorder.getLinesSigned();
		//
		if(linesEmployee.length == 0)
			throw new AdempiereException(Msg.translate(Env.getCtx(), "NoEmployee"));
		
		// hiring
		if(hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Hiring)){
			
			//
			selectedEmployee(linesEmployee.length);
			hrmempl = linesEmployee[0];

			hremp = X_HR_Employee.getHR_Employee(hrmempl.getC_BPartner_ID(),true);
	
			if(hremp.get_ID() == 0){
				// new
				hremp = new X_HR_Employee(getCtx(),0,null);
				hremp.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
				hremp.setC_BPartner_ID(hrmempl.getC_BPartner_ID());
				// hremp.setStartDate(hrmorder.getDateFrom()); - incorrect view 
				hremp.setStartDate(hrmorder.getStartDate());
				hremp.setEndDate(new Timestamp(maxDt.getMillis()));
				hremp.setHR_Department_ID(hrmorder.gethrm_departmentTo_ID());
				hremp.setHR_Job_ID(hrmorder.gethrm_tojob_ID());
				hremp.sethrm_wageRate_ID(hrmorder.gethrm_wageRate_ID());
				hremp.saveEx();
			}else{
				// update record
				hremp.setHR_Department_ID(hrmorder.gethrm_departmentTo_ID());
				hremp.setHR_Job_ID(hrmorder.gethrm_tojob_ID());
				hremp.saveUpdate();
			}
			
			/** update the values vacancy */
			wageRate = new MhrmwageRate(getCtx(), hrmorder.gethrm_wageRate_ID(), null);
			MHRJob job = new MHRJob(getCtx(), hrmorder.gethrm_tojob_ID(), get_TrxName());
			job.sethrm_vacancy(job.gethrm_vacancy().add(wageRate.gethrm_rate().negate()));
			job.sethrm_workplace(job.gethrm_workplace().add(wageRate.gethrm_rate()));
			job.saveEx();
			job = null;
			wageRate = null;
			
			/** automatic generate limit holiday*/
			holiDaylimit = Mhrmlimitholiday.getLimitHoliday(hrmempl.getC_BPartner_ID(), true);
			if(holiDaylimit == null)
				holiDaylimit = new Mhrmlimitholiday(getCtx(), 0, null);
			holiDaylimit.setC_BPartner_ID(hrmempl.getC_BPartner_ID());
			holiDaylimit.setStartDate(hrmorder.getStartDate());	
			// Determine the number of days in the interval of dates
			
			calendar.setTimeInMillis(hrmorder.getStartDate().getTime());
			calendar.add(Calendar.YEAR, +1);
			//
		    holiDaylimit.setEndDate(new Timestamp(calendar.getTimeInMillis()));
			holiDaylimit.sethrm_limitdays(Mhrmlimitholiday.LIMIT_VACATIONS);
			holiDaylimit.sethrm_daysused(0);
			holiDaylimit.setCloseDate(new Timestamp(minDt.getMillis()));
			holiDaylimit.saveEx();
			
			/** automatic generate contract */ 
			X_HR_Contract contract = new X_HR_Contract(getCtx(), 0, get_TrxName());
			contract.setName(hrmorder.getName());
			contract.setDescription(hrmorder.getBase());
			contract.sethrm_contractType(X_HR_Contract.HRM_CONTRACTTYPE_Labor);
			contract.setC_BPartner_ID(hrmempl.getC_BPartner_ID());
			contract.sethrm_order_ID(hrmorder.gethrm_order_ID());
			contract.sethrm_wageRate_ID(hrmorder.gethrm_wageRate_ID());
			contract.setHR_Department_ID(hrmorder.gethrm_departmentTo_ID());
			contract.setHR_Job_ID(hrmorder.gethrm_tojob_ID());
			contract.setValidFrom(hrmorder.getStartDate());
			contract.setValidTo(new Timestamp(Util.MAX_DATE.getMillis()));
			if(hrmorder.gethrm_trialperiod_ID() != 0){
				contract.sethrm_trialperiod_ID(hrmorder.gethrm_trialperiod_ID());
				//
				calendar.setTimeInMillis(hrmorder.getStartDate().getTime());
				calendar.add(Calendar.MONTH, +hrmorder.gethrm_trialperiod_ID());
				contract.setStartDate(hrmorder.getStartDate());
				contract.setEndDate(new Timestamp(calendar.getTimeInMillis()));
			}
				
			contract.saveEx();
			
			//
			hrmempl.setProcessed(true);
			hrmempl.saveEx();	
		}
		
		// vacation
		if(hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Vacation)
				|| hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Vacationadd)){
			//
			selectedEmployee(linesEmployee.length);
			hrmempl = linesEmployee[0];	
			
			// Vacation used days counting
			if (hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NormVacation)
					||hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NonNormVacation)){
					
				holiDaylimit = Mhrmlimitholiday.getLimitHoliday(hrmempl.getC_BPartner_ID(),true);				
				if(holiDaylimit == null)
					throw new AdempiereException("Vacation limit for person not set.");
								
				// Material aid sign
				if (hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NormVacation) )
					if(holiDaylimit.gethrm_order_ID() != 0)
						throw new AdempiereException("Material aids was given.");
				
				int days = Util.getWorkingDays(hrmempl.getC_BPartner_ID(), hrmorder.getStartDate(), hrmorder.getEndDate());
				
				//add by A.Kulantayev
				//long difference = hrmorder.getEndDate().getTime() - hrmorder.getStartDate().getTime(); //TODO Кастыль для лимита отпусков от 25-07-2013 14:30
				//int days = (int) (difference/(24*60*60*1000))+1;
				//if(days > (holiDaylimit.gethrm_days().intValue()+5)){
					//throw new AdempiereException("У сотрудника недостаточно накопленных дней! Можно для этого сотрудника дать отпуск максимум на "+(holiDaylimit.gethrm_days().intValue()+5)+" дней");	
				//}else{
				//
					
				// Holidays
				//holiDaylimit.sethrm_days(holiDaylimit.gethrm_days().add(new BigDecimal(days).negate()));
				//holiDaylimit.sethrm_limitdays(holiDaylimit.gethrm_limitdays() - days);
				holiDaylimit.sethrm_daysused(holiDaylimit.gethrm_daysused() + days);
				//}
				
				// Material aid sign
				if (hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NormVacation) ){
					holiDaylimit.sethrm_order_ID(hrmorder.gethrm_order_ID());
				}
				
//				Check used vacation period
				if ( holiDaylimit.getCloseDate().after(hrmorder.getStartDate())){
					throw new AdempiereException("You can take vacation after " + holiDaylimit.getCloseDate()); 
				}
				
				holiDaylimit.setCloseDate(hrmorder.getEndDate());
				holiDaylimit.saveEx();
			}			
			
//			int advance = 15;  // !!! Must remove into the setting table !!!
//			if (!hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_LeaveToCareForAChild) 
//					&& (days > holiDaylimit.gethrm_days().intValue() + advance))
//				throw new AdempiereException("Limit overflow, allowed " + holiDaylimit.gethrm_days().intValue() + " days");				
			
			// new absence record
			absence = new Mhrmabsence(getCtx(), 0, null);
			absence.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			absence.setC_BPartner_ID(hrmempl.getC_BPartner_ID());
			absence.setStartDate(hrmorder.getStartDate());
			absence.setEndDate(hrmorder.getEndDate());
			//
			if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NormVacation) ||
					hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NonNormVacation)){
				if (hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Vacation)){
					absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_Vacation);
				}else{
					absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_Vacationadd);
				}							

				// new vacation salary record
				vacation = new Mhrmvacation(getCtx(), 0, null);
				vacation.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
				vacation.sethrm_order_ID(hrmorder.get_ID());
				if (hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Vacation)){
					vacation.sethrm_ordertype(X_hrm_order.HRM_ORDERTYPE_Vacation);
					vacation.setName("Расчет отпуска работнику " + hrmempl.getC_BPartner().getName() + " по приказу: " + hrmorder.gethrm_number());
				}else{
					vacation.sethrm_ordertype(X_hrm_order.HRM_ORDERTYPE_Vacationadd);
					vacation.setName("Расчет продления отпуска работнику " + hrmempl.getC_BPartner().getName() + " по приказу: " + hrmorder.gethrm_number());
				}				
				
				vacation.setDateFrom(hrmorder.getDateFrom());
				vacation.saveEx();				
			}
			
			else if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_LeaveWithoutSalary))
				absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_LeaveWithoutSalary);
			else if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_Pregnancy))
				absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_Pregnancy);
			else if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_EducationLeave))
				absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_EducationLeave);
			else if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_LeaveToCareForAChild))
				if (hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Vacation)){
					absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_ChildCare);
				}else{
					absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_ChildCareAdd);
				}
				
			
			absence.sethrm_order_ID(hrmorder.get_ID());
			absence.saveEx();
			
			hrmempl.setProcessed(true);
			hrmempl.saveEx();	
		}
		
		// Boss vacation
		if(hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_BossVacation)){
			//
			selectedEmployee(linesEmployee.length);
			hrmempl = linesEmployee[0];	
			
			// Vacation used days counting
			if (hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NormVacation)
					|| hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NonNormVacation)){
					
				holiDaylimit = Mhrmlimitholiday.getLimitHoliday(hrmempl.getC_BPartner_ID(),true);				
				if(holiDaylimit == null)
					throw new AdempiereException("Vacation limit for person not set.");
								
//				// Material aid sign
//				if (hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NormVacation) )
//					if(holiDaylimit.gethrm_order_ID() != 0)
//						throw new AdempiereException("Material aids was given.");
//				
				int days = Util.getWorkingDays(hrmempl.getC_BPartner_ID(), hrmorder.getStartDate(), hrmorder.getEndDate());
				// Holidays
				holiDaylimit.sethrm_days(holiDaylimit.gethrm_days().add(new BigDecimal(days).negate()));
				holiDaylimit.sethrm_limitdays(holiDaylimit.gethrm_limitdays() - days);
				holiDaylimit.sethrm_daysused(holiDaylimit.gethrm_daysused() + days);
				
				// Material aid sign
				if (hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NormVacation) ){
					holiDaylimit.sethrm_order_ID(hrmorder.gethrm_order_ID());
				}
				
//				Check used vacation period
				if ( holiDaylimit.getCloseDate().after(hrmorder.getStartDate())){
					throw new AdempiereException("You can take vacation after " + holiDaylimit.getCloseDate()); 
				}
				
				holiDaylimit.setCloseDate(hrmorder.getEndDate());
				holiDaylimit.saveEx();
			}			
			
//			int advance = 15;  // !!! Must remove into the setting table !!!
//			if (!hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_LeaveToCareForAChild) 
//					&& (days > holiDaylimit.gethrm_days().intValue() + advance))
//				throw new AdempiereException("Limit overflow, allowed " + holiDaylimit.gethrm_days().intValue() + " days");				
			
			// new absence record
			absence = new Mhrmabsence(getCtx(), 0, null);
			absence.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			absence.setC_BPartner_ID(hrmempl.getC_BPartner_ID());
			absence.setStartDate(hrmorder.getStartDate());
			absence.setEndDate(hrmorder.getEndDate());
			//
			if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NormVacation) ||
					hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NonNormVacation)){
				absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_Vacation);				

				// new vacation salary record
				vacation = new Mhrmvacation(getCtx(), 0, null);
				vacation.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
				vacation.sethrm_order_ID(hrmorder.get_ID());
				vacation.sethrm_ordertype(X_hrm_order.HRM_ORDERTYPE_Vacation);
				vacation.setName("Расчет отпуска Председателю Правления " + hrmempl.getC_BPartner().getName() + " по приказу: " + hrmorder.gethrm_number());
				vacation.setDateFrom(hrmorder.getDateFrom());
				vacation.saveEx();				
			}
			
			else if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_LeaveWithoutSalary))
				absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_LeaveWithoutSalary);
			else if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_Pregnancy))
				absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_Pregnancy);
			else if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_EducationLeave))
				absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_EducationLeave);
			else if(hrmorder.gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_LeaveToCareForAChild))
				absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_ChildCare);
			
			absence.sethrm_order_ID(hrmorder.get_ID());
			absence.saveEx();
			
			hrmempl.setProcessed(true);
			hrmempl.saveEx();	
		}
		
		// Business Trip
		if(hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_BusinessTrip)
				|| hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_BossTrip)){
			
			for(Mhrmemployee empl: linesEmployee){
				// new absence record for each people
				absence = new Mhrmabsence(getCtx(), 0, null);
				absence.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
				absence.setC_BPartner_ID(empl.getC_BPartner_ID());
				absence.setStartDate(hrmorder.getStartDate());
				absence.setEndDate(hrmorder.getEndDate());
				
				if(hrmorder.gethrm_businesstriptype().equals(X_hrm_order.HRM_BUSINESSTRIPTYPE_CommonBusinessTrip))
					absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_BusinessTrip);
				if(hrmorder.gethrm_businesstriptype().equals(X_hrm_order.HRM_BUSINESSTRIPTYPE_EducationBusinessTrip))
					absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_EducationBusinessTrip);
				if(hrmorder.gethrm_businesstriptype().equals(X_hrm_order.HRM_BUSINESSTRIPTYPE_ChangesBusinessTrip))
					absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_ChangeBusinessTrip);
				
				absence.sethrm_order_ID(hrmorder.get_ID());
				absence.saveEx();
				empl.setProcessed(true);
				empl.saveEx();
			}
			// new business trip calculate window record
			btrip = new Mhrmbusinesstrip(getCtx(), 0, null);
			btrip.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			btrip.sethrm_order_ID(hrmorder.gethrm_order_ID());
			btrip.setDateFrom(hrmorder.getDateFrom());
			btrip.setName(hrmorder.getName());
			btrip.sethrm_ordertype(hrmorder.gethrm_ordertype());
			btrip.saveEx();			
		}
		
		// Dismissal
		if(hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Dismissal)){
			//
			selectedEmployee(linesEmployee.length);	
			hrmempl = linesEmployee[0];
			
			hremp = X_HR_Employee.getHR_Employee(hrmempl.getC_BPartner_ID(),true);
			if(hremp.get_ID() != 0){
				hremp.setEndDate(hrmorder.getStartDate());
				hremp.saveUpdate();
			}
			
			/* update the values vacancy */
			wageRate = new MhrmwageRate(getCtx(), hremp.gethrm_wageRate_ID(), null);
			MHRJob job = new MHRJob(getCtx(), hremp.getHR_Job_ID(), get_TrxName());
			job.sethrm_vacancy(job.gethrm_vacancy().add(wageRate.gethrm_rate()));
			job.sethrm_workplace(job.gethrm_workplace().add(wageRate.gethrm_rate().negate()));
			job.saveEx();
			job = null;
			wageRate = null;
			
			// new review calculate window record
			review = new Mhrmreview(getCtx(), 0, null);
			review.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			review.sethrm_order_ID(hrmorder.gethrm_order_ID());
			review.setDateFrom(hrmorder.getDateFrom());
			review.setName(hrmorder.getName());
			review.saveEx();
			
			//
			hrmempl.setProcessed(true);
			hrmempl.saveEx();
			
			//TODO--> кол-во накопленных дней отпуска
			//--start--add by A.Kulantayev При обработке приказа на расторжение трудового договора считаем кол-во накопленных дней отпуска
			Mhrmorder[] hiringOrder = Mhrmorder.getHRMOrderList(X_hrm_order.HRM_ORDERTYPE_Hiring, hrmempl.getC_BPartner_ID());
				//Считаем сколько раз он уходил в отпуск за все время что он работал
			Mhrmorder[] vacationOrders = Mhrmorder.getHRMOrderList(X_hrm_order.HRM_ORDERTYPE_Vacation, hrmempl.getC_BPartner_ID());
			int calendarVacationDays = 0; //кол-во использованных дней отпуска в календарных днях (Пока что только ежегодный трудовой отпуск)
			int workVacationDays = 0; //кол-во использованных дней отпуска в рабочих днях
			for(int i = 0; i< vacationOrders.length; i++){
				if(vacationOrders[i].gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NormVacation)
						||vacationOrders[i].gethrm_workleavetype().equals(X_hrm_order.HRM_WORKLEAVETYPE_NonNormVacation)){
					workVacationDays+=Mhrmvacation.getWorkTime(hrmempl.getC_BPartner_ID(), vacationOrders[i].getStartDate(), vacationOrders[i].getEndDate()); 
					calendarVacationDays+=Util.getWorkingDays(hrmempl.getC_BPartner_ID(), vacationOrders[i].getStartDate(), vacationOrders[i].getEndDate());
					
				}
			}
			
			int fullMonth = 0; //кол-во полных отработанных месяцев
			
			if(hiringOrder[0] != null){ //считаем кол-во полных отработанных месяцев
				long difference = hrmorder.getStartDate().getTime() - hiringOrder[0].getStartDate().getTime();// от большей даты минусуем меньшую дату (на самом деле находим разницу в милисекундах )
				int days = (int)(difference/(24*60*60*1000)); 
				fullMonth = (int)(days/30);
			}
			
			int totalCalendarDays = (int) Math.round(fullMonth*2.5 - calendarVacationDays);
						
			Calendar tempEndDate = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
			Calendar tempStartDate = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
			
			tempEndDate.setTime(hrmorder.getStartDate());
			tempStartDate.setTime(hrmorder.getStartDate());
			tempEndDate.set(Calendar.DATE, tempStartDate.get(Calendar.DATE)-1); //TODO нужно узнать что они понимают под днем уволнения!!!! если рабтник в день увольнения работает тогда нужно убрать -1 в другом случае, оставить!
			tempStartDate.set(Calendar.DATE, tempStartDate.get(Calendar.DATE)+1);
			//налогаем накомпленные в календарных днях дни компенсации на Календарь со дня увольнения сотрудника
			tempEndDate.set(Calendar.DATE, tempEndDate.get(Calendar.DATE)+totalCalendarDays);
			Timestamp d = new Timestamp(tempEndDate.getTimeInMillis());
			//---определяем кол-во праздничных дней за этот период
			String sql ="SELECT count(*) FROM hrm_schedulesettings_v WHERE C_Bpartner_ID = " +hrmempl.getC_BPartner_ID()+
					" AND DateFrom BETWEEN '" + new SimpleDateFormat("yyyy-MM-dd").format(hrmorder.getStartDate())+
					"' and '" + new SimpleDateFormat("yyyy-MM-dd").format(d) +
					"' AND Holidays_ID IS NOT NULL";
			int holidays = DB.getSQLValue(get_TrxName(), sql);
			
			tempEndDate.set(Calendar.DATE, tempEndDate.get(Calendar.DATE)+holidays);
			//--
			
			Timestamp edt = new Timestamp(tempEndDate.getTimeInMillis());
			
			//tempStartDate.setTime(edt);
			
			Timestamp sdt = new Timestamp(tempStartDate.getTimeInMillis());
		
			int compensionDays = Mhrmvacation.getWorkTime(hrmempl.getC_BPartner_ID(), sdt, edt);
			
			holiDaylimit = Mhrmlimitholiday.getLimitHoliday(hrmempl.getC_BPartner_ID(),true);
			holiDaylimit.sethrm_days(new BigDecimal(compensionDays));
			holiDaylimit.sethrm_limitdays(totalCalendarDays);
			holiDaylimit.saveEx();
			//--end--
			
		}
		
		// Moving
		if(hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Moving)){
			
			//
			selectedEmployee(linesEmployee.length);
			hrmempl = linesEmployee[0];
			
			if(hrmorder.gethrm_departmentTo_ID() == 0) errmsg.append(Util.requiredField(X_hrm_order.COLUMNNAME_hrm_departmentTo_ID)).append("\n");
			if(hrmorder.gethrm_departmentFrom_ID() == 0) errmsg.append(Util.requiredField(X_hrm_order.COLUMNNAME_hrm_departmentFrom_ID)).append("\n");
			if(hrmorder.gethrm_tojob_ID() == 0) errmsg.append(Util.requiredField(X_hrm_order.COLUMNNAME_hrm_tojob_ID)).append("\n");
			if(hrmorder.gethrm_fromjob_ID() == 0) errmsg.append(Util.requiredField(X_hrm_order.COLUMNNAME_hrm_fromjob_ID)).append("\n");
			//
			Util.checkErrMsg(errmsg);
			
			hremp = X_HR_Employee.getHR_Employee(hrmempl.getC_BPartner_ID(),true);
			if(hremp.get_ID() != 0){
				X_HR_Employee he = new X_HR_Employee(getCtx(),0,null);
				PO.copyValues(hremp, he);
				// close period				
				ShiftTime = hrmorder.getStartDate().getTime() - 1;				
				hremp.setEndDate(new Timestamp(ShiftTime));
				hremp.setIsActive(false);
				hremp.saveUpdate();
				// new record
				he.setStartDate(hrmorder.getStartDate());
				if(hrmorder.getEndDate() != null)
					he.setEndDate(hrmorder.getEndDate());
				else
					he.setEndDate(new Timestamp(Util.MAX_DATE.getMillis()));
				he.setHR_Department_ID(hrmorder.gethrm_departmentFrom_ID());
				he.setHR_Job_ID(hrmorder.gethrm_fromjob_ID());
				he.sethrm_wageRate_ID(hrmorder.gethrm_wageRate_ID());
				he.save();
			}
			
			/* update the values vacancy */
			wageRate = new MhrmwageRate(getCtx(), hremp.gethrm_wageRate_ID(), null);
			MHRJob jobTo = new MHRJob(getCtx(), hrmorder.gethrm_tojob_ID(), get_TrxName());
			jobTo.sethrm_vacancy(jobTo.gethrm_vacancy().add(wageRate.gethrm_rate()));
			jobTo.sethrm_workplace(jobTo.gethrm_workplace().add(wageRate.gethrm_rate().negate()));
			wageRate = null;
			//
			wageRate = new MhrmwageRate(getCtx(), hrmorder.gethrm_wageRate_ID(), null);
			MHRJob jobFrom = new MHRJob(getCtx(), hrmorder.gethrm_fromjob_ID(), get_TrxName());
			jobFrom.sethrm_vacancy(jobFrom.gethrm_vacancy().add(wageRate.gethrm_rate().negate()));
			jobFrom.sethrm_workplace(jobFrom.gethrm_workplace().add(wageRate.gethrm_rate()));
			//
			jobTo.saveEx();	jobFrom.saveEx();
			jobTo = null;	jobFrom = null;
		}
		
		// Premium
		if(hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Premium)
				|| hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Premium)){
			// new premium calculate window record
			bonus = new Mhrmbonus(getCtx(), 0, null);
			bonus.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
			bonus.sethrm_order_ID(hrmorder.gethrm_order_ID());
			bonus.setDateFrom(hrmorder.getDateFrom());
			bonus.setName(hrmorder.getName());
			bonus.sethrm_bonustype(hrmorder.gethrm_bonustype());
			bonus.saveEx();
			//
			for(Mhrmemployee empl: linesEmployee){
				empl.setProcessed(true);
				empl.saveEx();
			}
		}
		
		// Review
		if (hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Review)){
					
			for(Mhrmemployee empl: linesEmployee){
				//
				holiDaylimit = Mhrmlimitholiday.getLimitHoliday(empl.getC_BPartner_ID(),true);
				//
				hrmorderref = new Mhrmorder(getCtx(),hrmorder.gethrm_orderref_ID(),null);
				// new absence record
				Mhrmabsence absenceBase = Mhrmabsence.getAbsenceOrder(empl.getC_BPartner_ID(), hrmorderref.gethrm_order_ID());
				if(absenceBase == null)
					throw new AdempiereException("Не найден базовый приказ");
				
				ShiftTime = hrmorder.getStartDate().getTime() - 1;
				absenceBase.setEndDate(new Timestamp(ShiftTime));
				absenceBase.saveEx();
				
				absence = new Mhrmabsence(getCtx(), 0, null);
				absence.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
				absence.setC_BPartner_ID(empl.getC_BPartner_ID());
				absence.sethrm_order_ID(hrmorder.get_ID());				
				absence.setStartDate(hrmorder.getStartDate());				
				if (X_hrm_order.HRM_ORDERTYPE_Vacation.equals(hrmorderref.gethrm_ordertype())){
					absence.setEndDate(hrmorder.getEndDate());
					absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_ReviewFromVacation);					
				}else{
					absence.setEndDate(hrmorderref.getEndDate());
					absence.sethrm_absenceType(X_hrm_absence.HRM_ABSENCETYPE_ReviewFromTrip);					
				}					
				absence.saveEx();
				
				// new review calculate window record
				if (X_hrm_order.HRM_COMPENSATIONTYPE_Noncompensation.equals(hrmorder.gethrm_compensationtype())){
					review = new Mhrmreview(getCtx(), 0, null);
					review.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
					review.sethrm_order_ID(hrmorder.gethrm_order_ID());
					review.setDateFrom(hrmorder.getDateFrom());
					review.setName(hrmorder.getName());
					review.sethrm_review_ID(hrmorder.gethrm_orderref_ID());
					review.saveEx();
					
//					int days = Util.getDays(hrmorder.getStartDate(), hrmorder.getEndDate());
					
					//add by A.Kulantayev
					long difference = hrmorder.getEndDate().getTime() - hrmorder.getStartDate().getTime(); //TODO возвращяем сотруднику дни "Отзыв из отпуска без выдачи компенсации"
					int days = (int)(difference/(24*60*60*1000))+1;
					if(holiDaylimit.gethrm_days()==null)
						holiDaylimit.sethrm_days(holiDaylimit.gethrm_days().add(new BigDecimal(days)));
					//
					
					holiDaylimit.sethrm_limitdays(holiDaylimit.gethrm_limitdays() + days);
					holiDaylimit.sethrm_daysused(holiDaylimit.gethrm_daysused() - days);
					holiDaylimit.saveEx();
				}
				//
				hrmorder.sethrm_average(hrmorderref.gethrm_average());
				hrmorder.saveEx();
				//
				empl.setProcessed(true);
				empl.saveEx();
			}
		}
		
		// Overtime
		if (hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Overtime)){
			for(Mhrmemployee empl: linesEmployee){							
				int hours = Util.getHours(hrmorder.getStartTime(), hrmorder.getEndTime());
				attendance = Mhrmattendance.getAttendanceRec(empl.getC_BPartner_ID(), hrmorder.gethrm_order_ID());
				if (attendance == null || attendance.get_ID() == 0){
					attendance = new Mhrmattendance(getCtx(), 0, null);
					attendance.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
					attendance.setC_BPartner_ID(empl.getC_BPartner_ID());
					attendance.sethrm_hourquota(new BigDecimal(hours));						
					attendance.setStartDate(hrmorder.getStartDate());
					attendance.setEndDate(hrmorder.getEndDate());
					attendance.setDescription(hrmorder.gethrm_reason());
					attendance.sethrm_order_ID(hrmorder.get_ID());
					if (X_hrm_order.HRM_ORDERTYPE_Overtime.equals(hrmorder.gethrm_ordertype()))
						attendance.sethrm_attendanceType(X_hrm_attendance.HRM_ATTENDANCETYPE_Overtime);
					else
						attendance.sethrm_attendanceType(X_hrm_attendance.HRM_ATTENDANCETYPE_Weekends_Holidays);					
				}else{
					attendance.sethrm_hourquota(new BigDecimal(hours));						
					attendance.setStartDate(hrmorder.getStartDate());
					attendance.setEndDate(hrmorder.getEndDate());
					attendance.setDescription(hrmorder.gethrm_reason());
					if (X_hrm_order.HRM_ORDERTYPE_Overtime.equals(hrmorder.gethrm_ordertype()))
						attendance.sethrm_attendanceType(X_hrm_attendance.HRM_ATTENDANCETYPE_Overtime);
					else
						attendance.sethrm_attendanceType(X_hrm_attendance.HRM_ATTENDANCETYPE_Weekends_Holidays);
				}		
			
			attendance.saveEx();
			//
			empl.setProcessed(true);
			empl.saveEx();
			
			}
		}
		
		// Material aid
		if(hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_Materialaid)){
			for(Mhrmemployee empl: linesEmployee){		
			// new material aid calculate window record
					maid = new Mhrmmaterialaid(getCtx(), 0, null);
					maid.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
					maid.setName(hrmorder.getName());
					maid.setC_BPartner_ID(empl.getC_BPartner_ID());
					maid.setDateFrom(hrmorder.getDateFrom());
					maid.sethrm_order_ID(hrmorder.gethrm_order_ID());
					maid.sethrm_materialaidtype(hrmorder.gethrm_materialaidtype());
					if (hrmorder.getAmount().compareTo(new BigDecimal(0)) != 0){
						maid.sethrm_total(hrmorder.getAmount());						
					}else if (hrmorder.gethrm_mrp().compareTo(new BigDecimal(0)) != 0){
						BigDecimal MRP = Mhrmsettax.getRateValue(X_hrm_set_tax.HRM_TAXTYPE_MRP, hrmorder.getDateFrom());
						maid.sethrm_total(MRP.multiply(hrmorder.gethrm_mrp()));						
					}else{
						throw new AdempiereException(" Amount or MRP field not must be null ");
					}

					//					
					empl.setProcessed(true);
					empl.saveEx();
						
				    maid.saveEx();
			}
		}
		
		// Stoppage Of Wages
		if (hrmorder.gethrm_ordertype().equals(X_hrm_order.HRM_ORDERTYPE_StoppageOfWages)){				
			// new intercheckoff record
					inter = new Mhrmintercheckoff(getCtx(), 0, null);
					inter.setAD_Org_ID(Env.getAD_Org_ID(getCtx()));
					inter.setName(hrmorder.getName());			
					//inter.setC_BPartner_ID(empl.getC_BPartner_ID());
					inter.sethrm_order_ID(hrmorder.gethrm_order_ID());
					inter.sethrm_deductionType(hrmorder.gethrm_deductionType());
					inter.setDateFrom(hrmorder.getDateFrom());
					//inter.sethrm_total(hrmorder.getAmount());
					inter.saveEx();
					//
			for(Mhrmemployee empl: linesEmployee){	
					empl.setProcessed(true);
					empl.saveEx();			
			}
					
		}
		//
		for(Mhrmemployeessigned s: linesSigned){
			s.setProcessed(true);
			s.saveUpdate();
		}				
		
		//		
		hrmorder.setProcessing(true);
		//hrmorder.setProcessed(true);
		hrmorder.saveUpdate();
		
		return Msg.translate(getCtx(), "Success");
	}
	
}
